package net.scala.chapter3.c

import com.mongodb.{DBCursor, DBObject, DBCollection => MongoDBCollection}

class DBCollection(override val underlying: MongoDBCollection) extends ReadOnly

// MongoDB 特性：只读的
trait ReadOnly {
  val underlying: MongoDBCollection
  def name = underlying.getName
  def fullName = underlying.getFullName

  def find(query: Query): DBCursor = {
    def applyOptions(cursor: DBCursor, option: QueryOption): DBCursor = {
      option match {
        case Skip(skip, next) => applyOptions(cursor.skip(skip), next)
        case Sort(sorting, next) => applyOptions(cursor.sort(sorting), next)
        case Limit(limit, next) => applyOptions(cursor.limit(limit), next)
        case NoOption => cursor
      }
    }
    applyOptions(find(query.q), query.option)
  }

  def find(doc: DBObject): DBCursor = underlying find doc
  def findOne(doc: DBObject) = underlying.findOne(doc)
  def findOne = underlying.findOne
  def getCount(doc: DBObject) = underlying getCount doc
}

// MongoDB 特性：管理员权限的
trait Administrable extends ReadOnly {
  def drop(): Unit = underlying.drop()
  def dropIndexes(): Unit = underlying.dropIndexes()
}

// MongoDB 特性：可更新的
trait Updatable extends ReadOnly {
  def -=(doc: DBObject): Unit = underlying remove doc
  def +=(doc: DBObject): Unit = underlying save doc
}

// Mongo 特性：记忆(memorization)
trait Memoizer extends ReadOnly {
  val history = scala.collection.mutable.Map[Int, DBObject]()
  // 重载findOne方法
  override def findOne = {
    history.getOrElseUpdate(-1, {
      super.findOne
    })
  }
  override def findOne(doc: DBObject) = {
    history.getOrElseUpdate(doc.hashCode, {
      super.findOne(doc)
    })
  }
}

// Mongo 特性：国际化
trait LocaleAware extends ReadOnly {
  override def findOne(doc: DBObject) = {
    doc.put("locale", java.util.Locale.getDefault.getLanguage)
    super.findOne(doc)
  }

  override def find(doc: DBObject) = {
    doc.put("locale", java.util.Locale.getDefault.getLanguage)
    super.find(doc)
  }
}

// 这里定义了一个查询类，它可以实现正则匹配
case class Query(q: DBObject, option: QueryOption = NoOption) {
  def sort(sorting: DBObject) = Query(q, Sort(sorting, option))
  def skip(skip: Int) = Query(q, Skip(skip, option))
  def limit(limit: Int) = Query(q, Limit(limit, option))
}

// sealed关键字用于限制trait的继承，只有同文件的对象才能继承，并且包含异常
sealed trait QueryOption
case object NoOption extends QueryOption
// case class会自动生成对应的伴生对象(companion object)
case class Sort(sorting: DBObject, anotherOption: QueryOption) extends QueryOption
case class Skip(number: Int, anotherOption: QueryOption) extends QueryOption
case class Limit(limit: Int, anotherOption: QueryOption) extends QueryOption
